﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace VideoMagic.Extensions
{
    public static class FastArrayInitialize
    {
        public static void Fill<T>(this T[] myArray, T fillValue)
        {
            ArrayFill<T>(myArray, fillValue);
        }

        public static void Fill<T>(this T[] myArray, T[] fillValue)
        {
            ArrayFill<T>(myArray, fillValue);
        }

        //public static void ArrayFillTimed<T>(int myArrayLength, T[] fillValue)
        //{
        //    Stopwatch watch = new Stopwatch();
        //    T[] myArray1 = new T[myArrayLength];
        //    T[] myArray2 = new T[myArrayLength];

        //    watch.Restart();

        //    ArrayFillIterative<T>(myArray1, fillValue);
        //    watch.Stop();

        //    Debug.Print("Took {0} ticks or {1} milliseconds to iteratively fill an array of type {2} sized at {3}", watch.ElapsedTicks, watch.ElapsedMilliseconds,typeof(T).Name, myArray1.Length);

        //    watch.Restart();
        //    ArrayFill<T>(myArray2, fillValue);
        //    watch.Stop();

        //    Debug.Print("Took {0} ticks or {1} milliseconds to fill ArrayFill an array of type {2} sized at {3}", watch.ElapsedTicks, watch.ElapsedMilliseconds, typeof(T).Name, myArray2.Length);

        //    watch.Restart();
        //    myArray2.Fill(fillValue);
        //    watch.Stop();

        //    Debug.Print("Took {0} ticks or {1} milliseconds to fill ArrayFill an array of type {2} sized at {3}", watch.ElapsedTicks, watch.ElapsedMilliseconds, typeof(T).Name, myArray2.Length);


        //    watch.Restart();
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    ArrayFill<T>(myArray2, fillValue);
        //    watch.Stop();

        //    Debug.Print("Took {0} ticks or {1} milliseconds to fill ArrayFill an array of type {2} sized at {3}", watch.ElapsedTicks, watch.ElapsedMilliseconds, typeof(T).Name, myArray2.Length);

        //    watch.Restart();
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);
        //    myArray2.Fill(fillValue);

        //    watch.Stop();

        //    Debug.Print("Took {0} ticks or {1} milliseconds to fill ArrayFill an array of type {2} sized at {3}", watch.ElapsedTicks, watch.ElapsedMilliseconds, typeof(T).Name, myArray2.Length);

        //}

        public static void ArrayFill<T>(T[] arrayToFill, T fillValue)
        {
            // if called with a single value, wrap the value in an array and call the main function
            ArrayFill<T>(arrayToFill, new T[] { fillValue });
        }

        public static void ArrayFill<T>(T[] arrayToFill, T[] fillValue)
        {
            if (fillValue.Length >= arrayToFill.Length)
            {
                throw new ArgumentException("fillValue array length must be smaller than length of arrayToFill");
            }

            // set the initial array value
            Array.Copy(fillValue, arrayToFill, fillValue.Length);

            int arrayToFillHalfLength = arrayToFill.Length / 2;

            for (int i = fillValue.Length; i < arrayToFill.Length; i *= 2)
            {
                int copyLength = i;
                if (i > arrayToFillHalfLength)
                {
                    copyLength = arrayToFill.Length - i;
                }

                Array.Copy(arrayToFill, 0, arrayToFill, i, copyLength);
            }
        }



        //public static void ArrayFillIterative<T>(T[] arrayToFill, T fillValue)
        //{
        //    // if called with a single value, wrap the value in an array and call the main function
        //    ArrayFillIterative<T>(arrayToFill, new T[] { fillValue });
        //}

        //public static void ArrayFillIterative<T>(T[] arrayToFill, T[] fillValue)
        //{
        //    int counter = 0;
        //    int arrayLengthUsed = arrayToFill.Length - fillValue.Length;

        //    for (int i = 0; i < arrayLengthUsed; i += fillValue.Length)
        //    {
        //        for (int x = 0; x < fillValue.Length; x++)
        //        {
        //            counter = i + x;
        //            arrayToFill[counter] = fillValue[x];
        //        }
        //    }

        //    // fill remaining elements
        //    for (int i = counter + 1, x = 0; i < arrayToFill.Length; i++, x++)
        //    {
        //        arrayToFill[i] = fillValue[x];
        //    }
        //}

        //public static void ArrayExperiment<T>(T[] arrayToFill, T fillValue)
        //{
        //    arrayToFill.Initialize();
        //}
    }
}
